home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / ue312src.zip / FMRDOS.C < prev    next >
C/C++ Source or Header  |  1993-03-05  |  24KB  |  1,001 lines

  1. /*    FMRDOS.C:    Operating specific I/O and Spawning functions
  2.             under the MSDOS/FMR operating system
  3.             for MicroEMACS 3.12
  4.             (C)Copyright 1993 by Daniel M. Lawrence
  5. */
  6.  
  7. #include        <stdio.h>
  8. #include    "estruct.h"
  9. #include    "eproto.h"
  10.  
  11. #ifdef    MSDOS
  12. #include        "edef.h"
  13. #include    "elang.h"
  14.  
  15. /* The Mouse driver only works with typeahead defined */
  16. #if    MOUSE
  17. #undef    TYPEAH
  18. #define    TYPEAH    1
  19. #endif
  20.  
  21. #if  TURBO
  22. #include <conio.h>
  23. #include <dir.h>
  24. #include <dos.h>
  25. #include <bios.h>
  26.  
  27. struct ffblk fileblock;    /* structure for directory searches */
  28. #endif
  29. #if    MSC | IC
  30. #include <dos.h>
  31.  
  32. struct find_t fileblock;    /* structure for directory searches */
  33. #endif
  34.  
  35. #if     LATTICE | MSC | DTL | TURBO | IC | AZTEC | MWC
  36. union REGS rg;        /* cpu register for use of DOS calls */
  37. struct SREGS segreg;    /* cpu segment registers         */
  38. int nxtchar = -1;    /* character held from type ahead    */
  39. #endif
  40.  
  41. #if    MSC | TURBO | IC
  42. #include    <process.h>
  43. #endif
  44.  
  45. /*    Some global variable    */
  46. #define INBUFSIZ    40
  47. static int mexist;    /* is the mouse driver installed? */
  48. static int nbuttons;    /* number of buttons on the mouse */
  49. static int oldbut;    /* Previous state of mouse buttons */
  50. static int oldcol;    /* previous x position of mouse */
  51. static int oldrow;    /* previous y position of mouse */
  52.  
  53. PASCAL NEAR execprog(char *cmd);
  54.  
  55. /*    input buffers and pointers    */
  56.  
  57. #define    IBUFSIZE    64    /* this must be a power of 2 */
  58.  
  59. unsigned char in_buf[IBUFSIZE];    /* input character buffer */
  60. int in_next = 0;        /* pos to retrieve next input character */
  61. int in_last = 0;        /* pos to place most recent input character */
  62.  
  63. in_init()    /* initialize the input buffer */
  64.  
  65. {
  66.     in_next = in_last = 0;
  67. }
  68.  
  69. in_check()    /* is the input buffer non-empty? */
  70.  
  71. {
  72.     if (in_next == in_last)
  73.         return(FALSE);
  74.     else
  75.         return(TRUE);
  76. }
  77.  
  78. in_put(event)
  79.  
  80. int event;    /* event to enter into the input buffer */
  81.  
  82. {
  83.     in_buf[in_last++] = event;
  84.     in_last &= (IBUFSIZE - 1);
  85. }
  86.  
  87. int in_get()    /* get an event from the input buffer */
  88.  
  89. {
  90.     register int event;    /* event to return */
  91.  
  92.     event = in_buf[in_next++];
  93.     in_next &= (IBUFSIZE - 1);
  94.     return(event);
  95. }
  96.  
  97. /*
  98.  * This function is called once to set up the terminal device streams.
  99.  */
  100.  
  101. PASCAL NEAR ttopen()
  102.  
  103. {
  104. #if    MOUSE
  105.     long miaddr;    /* mouse interupt routine address */
  106. #endif
  107.     strcpy(os, "MSDOS");
  108.  
  109.     /* on all screens we are not sure of the initial position
  110.        of the cursor                    */
  111.     ttrow = 999;
  112.     ttcol = 999;
  113.  
  114. #if    MOUSE
  115.     /* check if the mouse drive exists first */
  116.     rg.x.ax = 0x3599;    /* look at the interrupt 99 address */
  117.  
  118. #if    MSC | TURBO | IC | DTL | LATTICE | MWC
  119.     int86x(0x21, &rg, &rg, &segreg);
  120.     miaddr = (((long)segreg.es) << 16) + (long)rg.x.bx;
  121.     if (miaddr == 0 || *(char * far)miaddr == 0xcf) {
  122. #endif
  123. #if    AZTEC
  124.     sysint(0x21, &rg, &rg);
  125.     miaddr = (((long)rg.x.es) << 16) + (long)rg.x.bx;
  126.     if (miaddr == 0 || *(char *)miaddr == 0xcf) {
  127. #endif
  128.         mexist = FALSE;
  129.         return;
  130.     }
  131.  
  132.     /* and then check for the mouse itself */
  133.     rg.x.ax = 0;        /* mouse status flag */
  134.     int86(0x99, &rg, &rg);    /* check for the mouse interupt */
  135.     mexist = (rg.x.ax == 0);
  136.     nbuttons = 3;        /* it COULD have 3 buttons?? */
  137.  
  138.     /* initialize our character input queue */
  139.     in_init();
  140.     if (mexist == FALSE)
  141.         return;
  142.  
  143.     /* if the mouse exists.. get it in the upper right corner */
  144.     rg.h.ah = 4;        /* set mouse cursor position */
  145.     oldcol = (term.t_ncol - 1);
  146.     rg.x.dx = 559;        /* last col of display */
  147.     oldrow = 0;
  148.     rg.x.bx = oldrow;        /* top row */
  149.     oldbut = 0;
  150.     int86(0x99, &rg, &rg);
  151. #else    /* !MOUSE */
  152.     mexist = 0;
  153. #endif    /* !MOUSE */
  154. }
  155.  
  156. maxlines(lines)        /* set number of vertical rows for mouse */
  157.  
  158. int lines;    /* # of vertical lines */
  159.  
  160. {
  161. #if    MOUSE
  162.     if (mexist) {
  163.         /* nothing yet! */
  164.     }
  165. #endif
  166. }
  167.  
  168. /*
  169.  * This function gets called just before we go back home to the command
  170.  * interpreter. On VMS it puts the terminal back in a reasonable state.
  171.  * Another no-operation on CPM.
  172.  */
  173. PASCAL NEAR ttclose()
  174. {
  175. }
  176.  
  177. /*
  178.  * Write a character to the display. On VMS, terminal output is buffered, and
  179.  * we just put the characters in the big array, after checking for overflow.
  180.  * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
  181.  * MS-DOS (use the very very raw console output routine).
  182.  */
  183.  
  184. PASCAL NEAR ttputc(c)
  185.  
  186. int c;
  187.  
  188. {
  189. #if     MWC
  190.         putcnb(c);
  191. #endif
  192.  
  193. #if    (LATTICE | AZTEC | TURBO | IC | MSC)
  194.     bdos(6, c, 0);
  195. #endif
  196. }
  197.  
  198. /*
  199.  * Flush terminal buffer. Does real work where the terminal output is buffered
  200.  * up. A no-operation on systems where byte at a time terminal I/O is done.
  201.  */
  202. PASCAL NEAR ttflush()
  203. {
  204. }
  205.  
  206. int doschar()    /* call the dos to get a char */
  207.  
  208. {
  209.  
  210.     register unsigned int c;    /* extended character to return */ 
  211.  
  212.     rg.h.ah = 7;        /* dos Direct Console Input call */
  213.     intdos(&rg, &rg);
  214.     return(rg.h.al & 255);
  215. }
  216.  
  217. /*
  218.  * Read a character from the terminal, performing no editing and doing no echo
  219.  * at all. Also mouse events are forced into the input stream here.
  220.  */
  221. PASCAL NEAR ttgetc()
  222.  
  223. {
  224.     register int c;        /* character read */
  225.  
  226. ttc:    /* return any keystrokes waiting in the
  227.        type ahead buffer */
  228.     if (in_check())
  229.         return(in_get());
  230.  
  231. #if    TYPEAH
  232.     if (typahead())
  233.         return(doschar());
  234.  
  235.     /* with no mouse, this is a simple get char routine */
  236.     if (mexist == FALSE || mouseflag == FALSE)
  237.         return(doschar());
  238.  
  239. #if    MOUSE
  240.     /* turn the mouse cursor on */
  241.     rg.x.ax = 0x0200;    /* Show Cursor */
  242.     int86(0x99, &rg, &rg);
  243.  
  244.     /* loop waiting for something to happen */
  245.     while (TRUE) {
  246.         if (typahead())
  247.             break;
  248.         if (checkmouse())
  249.             break;
  250.     }
  251.  
  252.     /* turn the mouse cursor back off */
  253.     rg.x.ax = 0x0201;    /* erase Cursor */
  254.     int86(0x99, &rg, &rg);
  255.  
  256.     goto ttc;
  257. #endif    /* MOUSE */
  258. #else    /* TYPEAH */
  259.     return(doschar());
  260. #endif    /* TYPEAH */
  261. }
  262.  
  263. #if    MOUSE
  264. checkmouse()
  265.  
  266. {
  267.     register int k;        /* current bit/button of mouse */
  268.     register int etype;    /* event type byte */
  269.     register int event;    /* encoded mouse event */
  270.     int mousecol;        /* current mouse column */
  271.     int mouserow;        /* current mouse row */
  272.     int sstate;        /* current shift key status */
  273.     int newbut;        /* new state of the mouse buttons */
  274.  
  275.     /* check to see if any mouse buttons are different */
  276.     rg.h.ah = 3;    /* Get button status and mouse position */
  277.     int86(0x99, &rg, &rg);
  278.     newbut   = rg.h.ch & 0x07;
  279.     mousecol = rg.x.dx /14;
  280.     mouserow = rg.x.bx /30;
  281.  
  282.     /* only notice changes */
  283.     if ((oldbut == newbut) && (mousecol == oldcol)
  284.         && (mouserow == oldrow))
  285.         return(FALSE);
  286.  
  287.     /* get the shift key status as well */
  288.     etype = MOUS >> 8;
  289.     sstate = 0;
  290.     rg.h.ah = 8;    /* return current shift status */
  291.     int86(0x90, &rg, &rg);
  292.     sstate = rg.h.al;
  293.     if (sstate & (4|32|64))        /* shifted? */
  294.         etype |= (SHFT >> 8);
  295.     if (sstate & 16)        /* controled? */
  296.         etype |= (CTRL >> 8);
  297.  
  298.     /* no buttons changes */
  299.     if (oldbut == newbut) {
  300.  
  301.         /* generate a mouse movement */
  302.         if (((mouse_move == 1) && (mmove_flag == TRUE)) ||
  303.             (mouse_move == 2)) {
  304.             in_put(0);
  305.             in_put(etype);
  306.             in_put(mousecol);
  307.             in_put(mouserow);
  308.             in_put('m');
  309.         }
  310.         oldcol = mousecol;
  311.         oldrow = mouserow;
  312.         return(TRUE);
  313.     }
  314.  
  315.     /* only on screen presses are legit! */
  316.     if (mousecol < 0)
  317.         mousecol = 0;
  318.     if (mouserow < 0)
  319.         mouserow = 0;
  320.  
  321.     for (k=1; k != (1 << nbuttons); k = k<<1) {
  322.  
  323.         /* For each button on the mouse */
  324.         if ((oldbut&k) != (newbut&k)) {
  325.  
  326.             /* This button changed, generate an event */
  327.             in_put(0);
  328.             in_put(etype);
  329.             in_put(mousecol);
  330.             in_put(mouserow);
  331.  
  332.             event = ((newbut&k) ? 0 : 1);    /* up or down? */
  333.             if (k == 2)            /* center button? */
  334.                 event += 4;
  335.             if (k == 4)            /* right button? */
  336.                 event += 2;
  337.             event += 'a';        /* plain */
  338.             in_put(event);
  339.             oldbut = newbut;
  340.             oldcol = mousecol;
  341.             oldrow = mouserow;
  342.             return(TRUE);
  343.         }
  344.     }
  345.     return(FALSE);
  346. }
  347. #endif
  348.  
  349. #if    TYPEAH
  350. /* typahead:    Check to see if any characters are already in the
  351.         keyboard buffer
  352. */
  353.  
  354. PASCAL NEAR typahead()
  355.  
  356. {
  357.     int flags;    /* cpu flags from dos call */
  358.  
  359. #if    TURBO | IC  /* This conditional portion added 9/13/89 by DRK. */
  360.     if (bioskey(1) == 0)
  361.         return FALSE;
  362.     else
  363.         return TRUE;
  364. #else
  365.     rg.x.ax = 0x4406;    /* IOCTL input status */
  366.     rg.x.bx = 0;        /* File handle = stdin */
  367. #if    MSC | DTL
  368.     int86(0x21,&rg,&rg);
  369.     flags = rg.h.al;
  370. #else
  371. #if    LATTICE | AZTEC | TURBO | IC
  372.     flags = intdos(&rg, &rg);
  373. #else
  374.     intcall(&rg, &rg, 0x21);
  375.     flags = rg.x.flags;
  376. #endif
  377. #endif
  378.     if (flags & 1)        /* AL = 0xFF if ready */
  379.         return(TRUE);
  380.     else
  381.         return(FALSE);
  382. #endif
  383. }
  384. #endif
  385.  
  386. /*
  387.  * Create a subjob with a copy of the command intrepreter in it. When the
  388.  * command interpreter exits, mark the screen as garbage so that you do a full
  389.  * repaint. Bound to "^X C".
  390.  */
  391.  
  392. PASCAL NEAR spawncli(f, n)
  393.  
  394. int f, n;
  395.  
  396. {
  397.     /* don't allow this command if restricted */
  398.     if (restflag)
  399.         return(resterr());
  400.  
  401.         movecursor(term.t_nrow, 0);             /* Seek to last line.   */
  402.         TTflush();
  403.     TTkclose();
  404.     shellprog("");
  405.     TTkopen();
  406.         sgarbf = TRUE;
  407.         return(TRUE);
  408. }
  409.  
  410. /*
  411.  * Run a one-liner in a subjob. When the command returns, wait for a single
  412.  * character to be typed, then mark the screen as garbage so a full repaint is
  413.  * done. Bound to "C-X !".
  414.  */
  415. PASCAL NEAR spawn(f, n)
  416.  
  417. int f, n;
  418.  
  419. {
  420.         register int s;
  421.         char line[NLINE];
  422.  
  423.     /* don't allow this command if restricted */
  424.     if (restflag)
  425.         return(resterr());
  426.  
  427.         if ((s=mlreply("!", line, NLINE)) != TRUE)
  428.                 return(s);
  429.     movecursor(term.t_nrow - 1, 0);
  430.     TTkclose();
  431.         shellprog(line);
  432.     TTkopen();
  433.     /* if we are interactive, pause here */
  434.     if (clexec == FALSE) {
  435.             mlputs(TEXT6);
  436. /*                     "\r\n\n[End]" */
  437.             tgetc();
  438.         }
  439.         sgarbf = TRUE;
  440.         return (TRUE);
  441. }
  442.  
  443. /*
  444.  * Run an external program with arguments. When it returns, wait for a single
  445.  * character to be typed, then mark the screen as garbage so a full repaint is
  446.  * done. Bound to "C-X $".
  447.  */
  448.  
  449. PASCAL NEAR execprg(f, n)
  450.  
  451. {
  452.         register int s;
  453.         char line[NLINE];
  454.  
  455.     /* don't allow this command if restricted */
  456.     if (restflag)
  457.         return(resterr());
  458.  
  459.         if ((s=mlreply("$", line, NLINE)) != TRUE)
  460.                 return(s);
  461.     movecursor(term.t_nrow - 1, 0);
  462.     TTkclose();
  463.         execprog(line);
  464.     TTkopen();
  465.     /* if we are interactive, pause here */
  466.     if (clexec == FALSE) {
  467.             mlputs(TEXT6);
  468. /*                     "\r\n\n[End]" */
  469.             tgetc();
  470.         }
  471.         sgarbf = TRUE;
  472.         return (TRUE);
  473. }
  474.  
  475. /*
  476.  * Pipe a one line command into a window
  477.  * Bound to ^X @
  478.  */
  479. PASCAL NEAR pipecmd(f, n)
  480.  
  481. int f, n;
  482.  
  483. {
  484.     register WINDOW *wp;    /* pointer to new window */
  485.     register BUFFER *bp;    /* pointer to buffer to zot */
  486.     register char *tmp;    /* ptr to TMP DOS environment variable */
  487.     FILE *fp;
  488.         char line[NLINE];    /* command line send to shell */
  489.     static char bname[] = "command";
  490.     static char filnam[NSTRING] = "command";
  491.     char *getenv();
  492.     FILE *fopen();
  493.  
  494.     /* don't allow this command if restricted */
  495.     if (restflag)
  496.         return(resterr());
  497.  
  498.     if ((tmp = getenv("TMP")) == NULL)
  499.         filnam[0] = 0;
  500.     else {
  501.         strcpy(filnam, tmp);
  502.         if (filnam[strlen(filnam) - 1] != '\\')
  503.             strcat(filnam, "\\");
  504.         }
  505.     strcat(filnam,"command");
  506.  
  507.     /* get the command to pipe in */
  508.         if (mlreply("@", line, NLINE) != TRUE)
  509.                 return(FALSE);
  510.  
  511.     /* get rid of the command output buffer if it exists */
  512.         if ((bp=bfind(bname, FALSE, 0)) != FALSE) {
  513.         /* try to make sure we are off screen */
  514.         wp = wheadp;
  515.         while (wp != NULL) {
  516.             if (wp->w_bufp == bp) {
  517.                 onlywind(FALSE, 1);
  518.                 break;
  519.             }
  520.             wp = wp->w_wndp;
  521.         }
  522.         /* get rid of the existing command buffer */
  523.         if (zotbuf(bp) != TRUE)
  524.             return(FALSE);
  525.     }
  526.  
  527.     /* redirect the command output to the output file */
  528.     strcat(line, " >>");
  529.     strcat(line, filnam);
  530.     movecursor(term.t_nrow - 1, 0);
  531.  
  532.     /* execute the command */
  533.     TTkclose();
  534.         shellprog(line);
  535.     TTkopen();
  536.         sgarbf = TRUE;
  537.  
  538.         /* did the output file get generated? */
  539.     if ((fp = fopen(filnam, "r")) == NULL)
  540.         return(FALSE);
  541.     fclose(fp);
  542.  
  543.     /* split the current window to make room for the command output */
  544.     if (splitwind(FALSE, 1) == FALSE)
  545.             return(FALSE);
  546.  
  547.     /* and read the stuff in */
  548.     if (getfile(filnam, FALSE) == FALSE)
  549.         return(FALSE);
  550.  
  551.     /* make this window in VIEW mode, update all mode lines */
  552.     curwp->w_bufp->b_mode |= MDVIEW;
  553.     wp = wheadp;
  554.     while (wp != NULL) {
  555.         wp->w_flag |= WFMODE;
  556.         wp = wp->w_wndp;
  557.     }
  558.  
  559.     /* and get rid of the temporary file */
  560.     unlink(filnam);
  561.     return(TRUE);
  562. }
  563.  
  564. /*
  565.  * filter a buffer through an external DOS program
  566.  * Bound to ^X #
  567.  */
  568. PASCAL NEAR filter(f, n)
  569.  
  570. int f, n;
  571.  
  572. {
  573.         register int    s;    /* return status from CLI */
  574.     register BUFFER *bp;    /* pointer to buffer to zot */
  575.         char line[NLINE];    /* command line send to shell */
  576.     char tmpnam[NFILEN];    /* place to store real file name */
  577.     static char bname1[] = "fltinp";
  578.  
  579.     static char filnam1[] = "fltinp";
  580.     static char filnam2[] = "fltout";
  581.  
  582.     /* don't allow this command if restricted */
  583.     if (restflag)
  584.         return(resterr());
  585.  
  586.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  587.         return(rdonly());    /* we are in read only mode    */
  588.  
  589.     /* get the filter name and its args */
  590.         if ((s=mlreply("#", line, NLINE)) != TRUE)
  591.                 return(s);
  592.  
  593.     /* setup the proper file names */
  594.     bp = curbp;
  595.     strcpy(tmpnam, bp->b_fname);    /* save the original name */
  596.     strcpy(bp->b_fname, bname1);    /* set it to our new one */
  597.  
  598.     /* write it out, checking for errors */
  599.     if (writeout(filnam1, "w") != TRUE) {
  600.         mlwrite(TEXT2);
  601. /*                      "[Cannot write filter file]" */
  602.         strcpy(bp->b_fname, tmpnam);
  603.         return(FALSE);
  604.     }
  605.  
  606.     strcat(line," <fltinp >fltout");
  607.     movecursor(term.t_nrow - 1, 0);
  608.     TTkclose();
  609.         shellprog(line);
  610.     TTkopen();
  611.         sgarbf = TRUE;
  612.     s = TRUE;
  613.  
  614.     /* on failure, escape gracefully */
  615.     if (s != TRUE || (readin(filnam2,FALSE) == FALSE)) {
  616.         mlwrite(TEXT3);
  617. /*                      "[Execution failed]" */
  618.         strcpy(bp->b_fname, tmpnam);
  619.         unlink(filnam1);
  620.         unlink(filnam2);
  621.         return(s);
  622.     }
  623.  
  624.     /* reset file name */
  625.     strcpy(bp->b_fname, tmpnam);    /* restore name */
  626.     bp->b_flag |= BFCHG;        /* flag it as changed */
  627.  
  628.     /* and get rid of the temporary file */
  629.     unlink(filnam1);
  630.     unlink(filnam2);
  631.     return(TRUE);
  632. }
  633.  
  634. #if    LATTICE
  635. extern int _oserr;
  636. #endif
  637.  
  638. #if    AZTEC | MWC
  639. extern int errno;
  640. #endif
  641.  
  642. #if    MSC
  643. extern int _doserrno;
  644. #endif
  645.  
  646. /*    SHELLPROG: Execute a command in a subshell        */
  647.  
  648. PASCAL NEAR shellprog(cmd)
  649.  
  650. char *cmd;    /*  Incoming command line to execute  */
  651.  
  652. {
  653.     char *shell;        /* Name of system command processor */
  654.     char swchar;        /* switch character to use */
  655.     union REGS regs;    /* parameters for dos call */
  656.     char comline[NSTRING];    /* constructed command line */
  657.     char *getenv();
  658.  
  659.     /*  detect current switch character and set us up to use it */
  660.     regs.h.ah = 0x37;    /*  get setting data  */
  661.     regs.h.al = 0x00;    /*  get switch character  */
  662.     intdos(®s, ®s);
  663.     swchar = (char)regs.h.dl;
  664.  
  665.     /*  get name of system shell  */
  666.     if ((shell = getenv("COMSPEC")) == NULL) {
  667.         return(FALSE);        /*  No shell located  */
  668.     }
  669.  
  670.     /* trim leading whitespace off the command */
  671.     while (*cmd == ' ' || *cmd == '\t')    /*  find out if null command */
  672.         cmd++;
  673.  
  674.     /**  If the command line is not empty, bring up the shell  **/
  675.     /**  and execute the command.  Otherwise, bring up the     **/
  676.     /**  shell in interactive mode.   **/
  677.  
  678.     if (*cmd) {
  679.         strcpy(comline, shell);
  680.         strcat(comline, " ");
  681.         comline[strlen(comline) + 1] = 0;
  682.         comline[strlen(comline)] = swchar;
  683.         strcat(comline, "c ");
  684.         strcat(comline, cmd);
  685.         return(execprog(comline));
  686.     } else
  687.         return(execprog(shell));
  688. }
  689.  
  690. /*    EXECPROG:    A function to execute a named program
  691.             with arguments
  692. */
  693.  
  694. #if    LATTICE | AZTEC | MWC
  695. #define    CFLAG    1
  696. #endif
  697.  
  698. PASCAL NEAR execprog(cmd)
  699.  
  700. char *cmd;    /*  Incoming command line to execute  */
  701.  
  702. {
  703.     char *sp;        /* temporary string pointer */
  704.     char f1[38];        /* FCB1 area (not initialized */
  705.     char f2[38];        /* FCB2 area (not initialized */
  706.     char prog[NSTRING];    /* program filespec */
  707.     char tail[NSTRING];    /* command tail with length byte */
  708.     union REGS regs;    /* parameters for dos call  */
  709. #if    MWC == 0
  710.     struct SREGS segreg;    /* segment registers for dis call */
  711. #endif
  712.     struct Pblock {        /* EXEC parameter block */
  713.         short envptr;    /* 2 byte pointer to environment string */
  714.         char *cline;    /* 4 byte pointer to command line */
  715.         char *fcb1;    /* 4 byte pointer to FCB at PSP+5Ch */
  716.         char *fcb2;    /* 4 byte pointer to FCB at PSP+6Ch */
  717.     } pblock;
  718.  
  719.     /* parse the command name from the command line */
  720.     sp = prog;
  721.     while (*cmd && (*cmd != ' ') && (*cmd != '\t'))
  722.         *sp++ = *cmd++;
  723.     *sp = 0;
  724.  
  725.     /* and parse out the command tail */
  726.     while (*cmd && ((*cmd == ' ') || (*cmd == '\t')))
  727.         ++cmd;
  728.     *tail = (char)(strlen(cmd)); /* record the byte length */
  729.     strcpy(&tail[1], cmd);
  730.     strcat(&tail[1], "\r");
  731.  
  732.     /* look up the program on the path trying various extentions */
  733.     if ((sp = flook(prog, TRUE)) == NULL)
  734.         if ((sp = flook(strcat(prog, ".exe"), TRUE)) == NULL) {
  735.             strcpy(&prog[strlen(prog)-4], ".com");
  736.             if ((sp = flook(prog, TRUE)) == NULL)
  737.                 return(FALSE);
  738.         }
  739.     strcpy(prog, sp);
  740.  
  741. #if    MWC == 0
  742.     /* get a pointer to this PSPs environment segment number */
  743.     segread(&segreg);
  744. #endif
  745.  
  746.     /* set up the EXEC parameter block */
  747.     pblock.envptr = 0;    /* make the child inherit the parents env */
  748.     pblock.fcb1 = f1;        /* point to a blank FCB */
  749.     pblock.fcb2 = f2;        /* point to a blank FCB */
  750.         pblock.cline = tail;        /* parameter line pointer */
  751.  
  752.     /* and make the call */
  753.     regs.h.ah = 0x4b;    /* EXEC Load or Execute a Program */
  754.     regs.h.al = 0x00;    /* load end execute function subcode */
  755. #if    AZTEC | MWC
  756.     regs.x.ds = ((unsigned long)(prog) >> 16);    /* program name ptr */
  757.     regs.x.dx = (unsigned int)(prog);
  758.     regs.x.es = regs.x.ds;
  759.     /*regs.x.es = ((unsigned long)(&pblock) >> 16);    * set up param block ptr */
  760.     regs.x.bx = (unsigned int)(&pblock);
  761. #endif
  762. #if    LATTICE | MSC | TURBO | IC | DTL
  763.     segreg.ds = ((unsigned long)(prog) >> 16);    /* program name ptr */
  764.     regs.x.dx = (unsigned int)(prog);
  765.     segreg.es = ((unsigned long)(&pblock) >> 16);    /* set up param block ptr */
  766.     regs.x.bx = (unsigned int)(&pblock);
  767. #endif
  768.  
  769. #if    NOVELL
  770.     rval = execpr(prog, &pblock);
  771. #endif
  772.     
  773. #if    LATTICE && (NOVELL == 0)
  774.     if ((intdosx(®s, ®s, &segreg) & CFLAG) == 0) {
  775.         regs.h.ah = 0x4d;    /* get child process return code */
  776.         intdos(®s, ®s);    /* go do it */
  777.         rval = regs.x.ax;    /* save child's return code */
  778.     } else
  779.         rval = -_oserr;        /* failed child call */
  780. #endif
  781. #if    AZTEC && (NOVELL == 0)
  782.     if ((sysint(0x21, ®s, ®s) & CFLAG) == 0) {
  783.         regs.h.ah = 0x4d;    /* get child process return code */
  784.         sysint(0x21, ®s, ®s);    /* go do it */
  785.         rval = regs.x.ax;    /* save child's return code */
  786.     } else
  787.         rval = -errno;        /* failed child call */
  788. #endif
  789. #if    MWC && (NOVELL == 0)
  790.     intcall(®s, ®s, DOSINT);
  791.     if ((regs.x.flags & CFLAG) == 0) {
  792.         regs.h.ah = 0x4d;    /* get child process return code */
  793.         intcall(®s, ®s, DOSINT);    /* go do it */
  794.         rval = regs.x.ax;    /* save child's return code */
  795.     } else
  796.         rval = -errno;        /* failed child call */
  797. #endif
  798. #if    (TURBO | IC | MSC | DTL) && (NOVELL == 0)
  799.     intdosx(®s, ®s, &segreg);
  800.     if (regs.x.cflag == 0) {
  801.         regs.h.ah = 0x4d;    /* get child process return code */
  802.         intdos(®s, ®s);    /* go do it */
  803.         rval = regs.x.ax;    /* save child's return code */
  804.     } else
  805.         rval = -_doserrno;    /* failed child call */
  806. #endif
  807.     return((rval < 0) ? FALSE : TRUE);
  808. }
  809.  
  810. /* return a system dependant string with the current time */
  811.  
  812. char *PASCAL NEAR timeset()
  813.  
  814. {
  815. #if    MWC | TURBO | IC | MSC
  816.     register char *sp;    /* temp string pointer */
  817.     char buf[16];        /* time data buffer */
  818.     extern char *ctime();
  819.  
  820.     time(buf);
  821.     sp = ctime(buf);
  822.     sp[strlen(sp)-1] = 0;
  823.     return(sp);
  824. #else
  825.     return(errorm);
  826. #endif
  827. }
  828.  
  829. #if    TURBO | IC
  830. /*    FILE Directory routines        */
  831.  
  832. char path[NFILEN];    /* path of file to find */
  833. char rbuf[NFILEN];    /* return file buffer */
  834.  
  835. /*    do a wild card directory search (for file name completion) */
  836.  
  837. char *PASCAL NEAR getffile(fspec)
  838.  
  839. char *fspec;    /* pattern to match */
  840.  
  841. {
  842.     register int index;        /* index into various strings */
  843.     register int point;        /* index into other strings */
  844.     register int extflag;        /* does the file have an extention? */
  845.     char fname[NFILEN];        /* file/path for DOS call */
  846.  
  847.     /* first parse the file path off the file spec */
  848.     strcpy(path, fspec);
  849.     index = strlen(path) - 1;
  850.     while (index >= 0 && (path[index] != '/' &&
  851.                 path[index] != '\\' && path[index] != ':'))
  852.         --index;
  853.     path[index+1] = 0;
  854.  
  855.     /* check for an extension */
  856.     point = strlen(fspec) - 1;
  857.     extflag = FALSE;
  858.     while (point > index) {
  859.         if (fspec[point] == '.') {
  860.             extflag = TRUE;
  861.             break;
  862.         }
  863.         point--;
  864.     }
  865.  
  866.     /* construct the composite wild card spec */
  867.     strcpy(fname, path);
  868.     strcat(fname, &fspec[index+1]);
  869.     strcat(fname, "*");
  870.     if (extflag == FALSE)
  871.         strcat(fname, ".*");
  872.  
  873.     /* and call for the first file */
  874.     if (findfirst(fname, &fileblock, FA_DIREC) == -1)
  875.         return(NULL);
  876.  
  877.     /* return the first file name! */
  878.     strcpy(rbuf, path);
  879.     strcat(rbuf, fileblock.ff_name);
  880.     mklower(rbuf);
  881.     if (fileblock.ff_attrib == 16)
  882.         strcat(rbuf, DIRSEPSTR);
  883.     return(rbuf);
  884. }
  885.  
  886. char *PASCAL NEAR getnfile()
  887.  
  888. {
  889.     register int index;        /* index into various strings */
  890.     register int point;        /* index into other strings */
  891.     register int extflag;        /* does the file have an extention? */
  892.     char fname[NFILEN];        /* file/path for DOS call */
  893.  
  894.     /* and call for the first file */
  895.     if (findnext(&fileblock) == -1)
  896.         return(NULL);
  897.  
  898.     /* return the first file name! */
  899.     strcpy(rbuf, path);
  900.     strcat(rbuf, fileblock.ff_name);
  901.     mklower(rbuf);
  902.     if (fileblock.ff_attrib == 16)
  903.         strcat(rbuf, DIRSEPSTR);
  904.     return(rbuf);
  905. }
  906. #else
  907. #if    MSC
  908. /*    FILE Directory routines        */
  909.  
  910. char path[NFILEN];    /* path of file to find */
  911. char rbuf[NFILEN];    /* return file buffer */
  912.  
  913. /*    do a wild card directory search (for file name completion) */
  914.  
  915. char *PASCAL NEAR getffile(fspec)
  916.  
  917. char *fspec;    /* pattern to match */
  918.  
  919. {
  920.     register int index;        /* index into various strings */
  921.     register int point;        /* index into other strings */
  922.     register int extflag;        /* does the file have an extention? */
  923.     char fname[NFILEN];        /* file/path for DOS call */
  924.  
  925.     /* first parse the file path off the file spec */
  926.     strcpy(path, fspec);
  927.     index = strlen(path) - 1;
  928.     while (index >= 0 && (path[index] != '/' &&
  929.                 path[index] != '\\' && path[index] != ':'))
  930.         --index;
  931.     path[index+1] = 0;
  932.  
  933.     /* check for an extension */
  934.     point = strlen(fspec) - 1;
  935.     extflag = FALSE;
  936.     while (point > index) {
  937.         if (fspec[point] == '.') {
  938.             extflag = TRUE;
  939.             break;
  940.         }
  941.         point--;
  942.     }
  943.  
  944.     /* construct the composite wild card spec */
  945.     strcpy(fname, path);
  946.     strcat(fname, &fspec[index+1]);
  947.     strcat(fname, "*");
  948.     if (extflag == FALSE)
  949.         strcat(fname, ".*");
  950.  
  951.     /* and call for the first file */
  952.     if (_dos_findfirst(fname, _A_NORMAL|_A_SUBDIR, &fileblock) != 0)
  953.         return(NULL);
  954.  
  955.     /* return the first file name! */
  956.     strcpy(rbuf, path);
  957.     strcat(rbuf, fileblock.name);
  958.     mklower(rbuf);
  959.     if (fileblock.attrib == 16)
  960.         strcat(rbuf, DIRSEPSTR);
  961.     return(rbuf);
  962. }
  963.  
  964. char *PASCAL NEAR getnfile()
  965.  
  966. {
  967.     register int index;        /* index into various strings */
  968.     register int point;        /* index into other strings */
  969.     register int extflag;        /* does the file have an extention? */
  970.     char fname[NFILEN];        /* file/path for DOS call */
  971.  
  972.     /* and call for the first file */
  973.     if (_dos_findnext(&fileblock) != 0)
  974.         return(NULL);
  975.  
  976.     /* return the first file name! */
  977.     strcpy(rbuf, path);
  978.     strcat(rbuf, fileblock.name);
  979.     mklower(rbuf);
  980.     if (fileblock.attrib == 16)
  981.         strcat(rbuf, DIRSEPSTR);
  982.     return(rbuf);
  983. }
  984. #else
  985. char *PASCAL NEAR getffile(fspec)
  986.  
  987. char *fspec;    /* file to match */
  988.  
  989. {
  990.     return(NULL);
  991. }
  992.  
  993. char *PASCAL NEAR getnfile()
  994.  
  995. {
  996.     return(NULL);
  997. }
  998. #endif
  999. #endif
  1000. #endif
  1001.